using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;

using WozLib.UI.Ink.SketchProperties;
using System.Diagnostics;
using System.Windows.Media.Imaging;
using System.IO;
using WozLib.Net;
using System.Net;
using WozLib.UI.Ink.SketchObjects;
using System.Windows.Input;


namespace WozLib.UI.Ink.SketchElements
{
  public class SketchText : Canvas, ISketchObject
  {
    public static SketchText FromTextWozObject(TextSketchObject textWozObject)
    {
      SketchPropertyCollection wozPropertyCollection = new SketchPropertyCollection();
      wozPropertyCollection.WozProperties = textWozObject.WozProperties;

      return new SketchText(textWozObject.WozID, wozPropertyCollection);
    }

    private static TextBox GetDefaultTextBox(Canvas canvas)
    {
      return GetDefaultTextBox(new Rect(new Point(0.0, 0.0), new Point(1.0, 1.0)), canvas, "text");
    }

    private static TextBox GetDefaultTextBox(Rect rect, Canvas canvas, string text)
    {

      TextBox textBox = new TextBox();
      textBox.FontSize = 12.0;
      textBox.FontFamily = new FontFamily("Verdana");
      textBox.TextWrapping = TextWrapping.Wrap;
      textBox.AcceptsReturn = true;
      textBox.AcceptsTab = true;
      textBox.Text = text;
      textBox.Foreground = Brushes.Black;
      textBox.SetValue(Canvas.LeftProperty, 0.0);
      textBox.SetValue(Canvas.TopProperty, 0.0);
      textBox.Width = rect.Width;
      textBox.Height = rect.Height;
      canvas.Width = rect.Width;
      canvas.Height = rect.Height;
      canvas.SetValue(InkCanvas.LeftProperty, rect.X);
      canvas.SetValue(InkCanvas.TopProperty, rect.Y);
      //textBox.BorderBrush = Brushes.Transparent;
      if (false)
      {
        //textBox.BorderThickness = 0.0;
      }
      else
      {
        //textBox.BorderThickness = 0.0;
        textBox.Background = Brushes.Transparent;
      }
      
      canvas.Children.Add(textBox);
      return textBox;
    }

    public event TextChangedEventHandler TextChanged;

    public TextBox TextBox
    {
      get { return _TextBox;}
      set { _TextBox = value; }
    } private TextBox _TextBox;

    private static TextBlock GetDefaultTextBlock(Canvas canvas)
    {
      return GetDefaultTextBlock(new Rect(new Point(0.0, 0.0), new Point(1.0, 1.0)), canvas, "text");
    }

    private static TextBlock GetDefaultTextBlock(Rect rect, Canvas canvas, string text)
    {

      TextBlock textBlock = new TextBlock();
      textBlock.FontSize = 12.0;
      textBlock.FontFamily = new FontFamily("Verdana");
      textBlock.TextWrapping = TextWrapping.Wrap;
      textBlock.Text = text;
      textBlock.Foreground = Brushes.Black;
      textBlock.SetValue(Canvas.LeftProperty, 0.0);
      textBlock.SetValue(Canvas.TopProperty, 0.0);
      textBlock.Width = rect.Width;
      textBlock.Height = rect.Height;
      canvas.Width = rect.Width;
      canvas.Height = rect.Height;
      canvas.SetValue(InkCanvas.LeftProperty, rect.X);
      canvas.SetValue(InkCanvas.TopProperty, rect.Y);
      //textBox.BorderBrush = Brushes.Transparent;
      if (false)
      {
        //textBox.BorderThickness = 0.0;
      }
      else
      {
        //textBox.BorderThickness = 0.0;
        textBlock.Background = Brushes.Transparent;
      }

      canvas.Children.Add(textBlock);
      return textBlock;
    }

    public TextBlock TextBlock
    {
      get { return _TextBlock; }
      set { _TextBlock = value; }
    } private TextBlock _TextBlock;

    public SketchText()
      : this(new Rect(new Point(0.0,0.0),new Point(1.0,1.0)),null)
    {
    }

    public SketchText(Rect rect, SketchObjectRegistry wozObjectRegistry) : this (rect,wozObjectRegistry, null)
    {
    }

    public SketchText(Rect rect, SketchObjectRegistry wozObjectRegistry, string text)
    {

      if (text != null)
      {
        TextBox = GetDefaultTextBox(rect, this, text);
        TextBlock = GetDefaultTextBlock(rect, this, text);

        //try
        //{
        //  // try to create an image from the url
        //  BitmapImage bitmapImage = new BitmapImage(new Uri(imageUrl));

        //  // make the rectangle's fill the image
        //  TextBox.Background = new ImageBrush(bitmapImage);
        //  TextBlock.Background = new ImageBrush(bitmapImage);
        //}
        //catch (Exception ex)
        //{
        //  Debug.WriteLine(ex);
        //}
      }
      else
      {
        TextBox = GetDefaultTextBox(rect, this, "text");
        TextBlock = GetDefaultTextBlock(rect, this, "text");
      }

      // register this object
      if (wozObjectRegistry != null)
      {
        wozObjectRegistry.RegisterObject(this);
      }
      else
      {
        
      }

      TextBox.Visibility = Visibility.Visible;
      TextBlock.Visibility = Visibility.Hidden;
      TextBox.TextChanged += new TextChangedEventHandler(TextBox_TextChanged);

      TextBox.GotFocus += new RoutedEventHandler(_TextBox_SelectAll_GotFocus);
      TextBox.PreviewMouseDown += new System.Windows.Input.MouseButtonEventHandler(_TextBox_SelectAll_PreviewMouseDown);

      // Set all of our WozPropertyCollection properties

      FontSizeSketchProperty fontSizeProperty = new FontSizeSketchProperty(TextBox.FontSize, WozPropertyType.FontSize);
      this.SetProperty(fontSizeProperty);

      StringSketchProperty fontWozProperty = new StringSketchProperty(TextBox.FontFamily.ToString(), WozPropertyType.Font);
      this.SetProperty(fontWozProperty);

      if (TextBox.Visibility == Visibility.Visible)
      {
        BooleanSketchProperty booleanWozProperty = new BooleanSketchProperty(true, WozPropertyType.Editable);
        this.SetProperty(booleanWozProperty);
      }
      else
      {
        BooleanSketchProperty booleanWozProperty = new BooleanSketchProperty(false, WozPropertyType.Editable);
        this.SetProperty(booleanWozProperty);
      }

      if (TextBox.Text != null)
      {
        StringSketchProperty stringWozProperty = new StringSketchProperty(TextBox.Text, WozPropertyType.Text);
        this.SetProperty(stringWozProperty);
      }

      if (TextBox.Background is SolidColorBrush)
      {
        ColorSketchProperty colorWozPropertyFill = new ColorSketchProperty((TextBox.Background as SolidColorBrush).Color, WozPropertyType.FillColor);
        this.SetProperty(colorWozPropertyFill);
      }
      //else if (TextBox.Background is ImageBrush)
      //{
      //  StringWozProperty stringWozProperty = new StringWozProperty(imageUrl,WozPropertyType.FillImageUrl);
      //  this.SetProperty(stringWozProperty);
      //}

      if (TextBox.Foreground is SolidColorBrush)
      {
        ColorSketchProperty colorWozPropertyFill = new ColorSketchProperty((TextBox.Foreground as SolidColorBrush).Color, WozPropertyType.ForegroundColor);
        this.SetProperty(colorWozPropertyFill);
      }
      //else if (TextBox.Foreground is ImageBrush)
      //{
      //  StringWozProperty stringWozProperty = new StringWozProperty(imageUrl, WozPropertyType.ForegroundImageUrl);
      //  this.SetProperty(stringWozProperty);
      //}

      // set the points
      RectGeometrySketchProperty rectGeometryWozProperty = new RectGeometrySketchProperty(rect, WozPropertyType.RectGeometry);
      this.SetProperty(rectGeometryWozProperty);
    }

    /// <summary>
    /// if the calling textbox is not focused, this method focuses the textbox
    /// and selects all the text. One would use this method as the PreviewMouseDown
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is clicked once.
    /// 
    /// We cannot use GotFocus because the click handler will unselect the text and
    /// place the cursor at the click point
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void _TextBox_SelectAll_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
      // if it was a textbox that was clicked and its not selected
      if (sender is TextBox && !(sender as TextBox).IsFocused)
      {
        // select all the text
        (sender as TextBox).SelectAll();

        // give the textbox input focus
        (sender as TextBox).Focus();

        // set handled to true to prevent the regular textbox click code from running
        e.Handled = true;
      }
    }

    /// <summary>
    /// this method focuses the textbox and selects all the text. 
    /// One would use this method as the GotFocus
    /// for textboxes where they want the user to just be able to type a new
    /// value after the textbox is tabbed into.
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void _TextBox_SelectAll_GotFocus(object sender, RoutedEventArgs e)
    {
      if (sender is TextBox)
      {
        // select all the text
        (sender as TextBox).SelectAll();
      }
    }

    private bool _textChanging = false;
    void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
      if (!_textChanging)
      {
        _textChanging = true;

        //this.SetProperty(new StringWozProperty(TextBox.Text, WozPropertyType.Text));
        TextBlock.Text = TextBox.Text;
        if (TextChanged != null)
        {
          TextChanged(this, e);
        }

        _textChanging = false;
      }
    }

    public SketchText(long id, SketchPropertyCollection wozPropertyCollection)
      : this(id, wozPropertyCollection, null)
    {
    }

    public SketchText(long id, SketchPropertyCollection wozPropertyCollection, SketchObjectRegistry wozObjectRegistry)
      : base()
    {

      TextBox = GetDefaultTextBox(this);
      TextBlock = GetDefaultTextBlock(this);

      TextBox.Visibility = Visibility.Visible;
      TextBlock.Visibility = Visibility.Hidden;
      TextBox.TextChanged += new TextChangedEventHandler(TextBox_TextChanged);

      TextBox.GotFocus += new RoutedEventHandler(_TextBox_SelectAll_GotFocus);
      TextBox.PreviewMouseDown += new System.Windows.Input.MouseButtonEventHandler(_TextBox_SelectAll_PreviewMouseDown);

      // assign our ID before we doing anything else
      this._WozID = id;

      // overwrite our blank collection with the provided one
      this._WozPropertyCollection = wozPropertyCollection;

      // all of our properties can be set this way
      SetProperty(wozPropertyCollection.WozProperties);

      // register this object
      if (wozObjectRegistry != null)
      {
        wozObjectRegistry.RegisterObjectWithExisitingId(this);
      }
    }

    #region IWozObject Members

    // our private way of holding an ID
    private long _WozID = long.MinValue;

    public long WozID
    {
      get 
      {
        return _WozID;
      }
      set
      {
        _WozID = value;
      }
    }

    // our private way of holding properties
    protected SketchPropertyCollection _WozPropertyCollection = new SketchPropertyCollection();

    // You should update your properties to reflect the actualy state of your underlying object
    // i.e if your current color property says Black, but your stroke actually had its color
    // changed to Red recently - change the color property to red
    public void SyncProperties()
    {
      SyncProperties(_WozPropertyCollection);
    }

    // You should update your properties to reflect the actualy state of your underlying object
    // i.e if your current color property says Black, but your stroke actually had its color
    // changed to Red recently - change the color property to red
    protected void SyncProperties(SketchPropertyCollection wozPropertyCollection)
    {
      RectGeometrySketchProperty rectGeometryWozProperty = new RectGeometrySketchProperty(
        new Rect((double)GetValue(InkCanvas.LeftProperty),(double)GetValue(InkCanvas.TopProperty),this.Width,this.Height),
        WozPropertyType.RectGeometry);
      SetProperty(rectGeometryWozProperty);

      this.SetProperty(new StringSketchProperty(TextBox.Text, WozPropertyType.Text));
    }

    // Set the property, but also make the corresponding change to the underlying object
    // i.e. if the color property is set on a stroke, actually change the drawing attributes
    public void SetProperty(WozLib.UI.Ink.SketchProperties.SketchProperty wozProperty)
    {
      _WozPropertyCollection.SetProperty(wozProperty);

      UpdateProperty(wozProperty);
    }

    private void UpdateProperty(WozLib.UI.Ink.SketchProperties.SketchProperty wozProperty)
    {
      try
      {
        // Figure out what we should with this property
        switch (wozProperty.WozPropertyType)
        {
          case WozPropertyType.Font:
            TextBox.FontFamily = new FontFamily((wozProperty as StringSketchProperty).Data);
            TextBlock.FontFamily = new FontFamily((wozProperty as StringSketchProperty).Data);
            break;
          case WozPropertyType.FontSize:
            TextBox.FontSize = (wozProperty as FontSizeSketchProperty).Data;
            TextBlock.FontSize = (wozProperty as FontSizeSketchProperty).Data;
            break;
          case WozPropertyType.FillColor:
            TextBox.Background = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            TextBlock.Background = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            break;
          case WozPropertyType.ForegroundColor:
            TextBox.Foreground = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            TextBlock.Foreground = new SolidColorBrush((wozProperty as ColorSketchProperty).Data);
            break;
          case WozPropertyType.FillImageUrl:
            try
            {
              // try to create an image from the url
              BitmapImage bitmapImage = new BitmapImage(new Uri((wozProperty as StringSketchProperty).Data));


              // make the rectangle's fill the image
              ImageBrush ib = new ImageBrush(bitmapImage);
              TextBox.Background = ib;
              TextBlock.Background = ib;
              this.InvalidateVisual();
              //Rectangle.InvalidateVisual();
            }
            catch (Exception ex)
            {
              Debug.WriteLine(ex);
            }
            break;
          case WozPropertyType.RectGeometry:
            Rect rect = (wozProperty as RectGeometrySketchProperty).Rect;

            this.SetValue(InkCanvas.LeftProperty, rect.X);
            this.SetValue(InkCanvas.TopProperty, rect.Y);
            this.TextBlock.Width = rect.Width;
            this.TextBlock.Height = rect.Height;
            this.TextBox.Width = rect.Width;
            this.TextBox.Height = rect.Height;
            this.Width = rect.Width;
            this.Height = rect.Height;
            break;
          case WozPropertyType.Text:
            if (!_textChanging)
            {
              _textChanging = true;

              string text = (wozProperty as StringSketchProperty).Data;

              TextBox.Text = text;
              TextBlock.Text = text;

              _textChanging = false;
            }
            break;
          case WozPropertyType.Editable:
            bool editable = (wozProperty as BooleanSketchProperty).Data;
            if (editable)
            {
              TextBlock.Visibility = Visibility.Hidden;
              TextBox.Visibility = Visibility.Visible;
            }
            else
            {
              TextBox.Visibility = Visibility.Hidden;
              TextBlock.Visibility = Visibility.Visible;
            }
            break;
          case WozPropertyType.Bounds:
            // don't know how right now
            break;

          default:
            // This shouldn't happen
            Debug.WriteLine(this.ToString() + " doesn't know what to do with a " + wozProperty.WozPropertyType.ToString());
            break;
        }
      }
      catch (Exception ex)
      {
        Debug.WriteLine("SketchLine: Property Setting Failed: " + ex.ToString());
      }
    }

    public void SetProperty(IEnumerable<WozLib.UI.Ink.SketchProperties.SketchProperty> wozProperties)
    {
      foreach (SketchProperty wozProperty in wozProperties)
      {
        SetProperty(wozProperty);
      }
    }

    // just return the specified property
    public SketchProperty GetProperty(WozPropertyType wozPropertyType)
    {
      return _WozPropertyCollection.GetProperty(wozPropertyType);
    }

    // WozPropertyCollection makes a copy for us
    public IEnumerable<SketchProperty> GetProperties()
    {
      return _WozPropertyCollection.WozProperties;
    }

    // Make sure we create the WozObject from the appropriate derived class (LineWozObject)
    public SketchObject GetWozObject()
    {
      return new TextSketchObject(WozID, GetProperties());
    }

    #endregion

    #region IWozObject Members


    // maybe i should just check to see if this is in our bounds?
    public bool ShouldErase(Point pointRelativeToUie)
    {
      if (this.InputHitTest(pointRelativeToUie) != null)
      {
        return true;
      }
      else
      {
        return false;
      }
    }

    #endregion
  }
}
